package com.roy.eureka.client.controller;

import java.util.ArrayList;
import java.util.List;

import javax.annotation.Resource;
import javax.websocket.server.PathParam;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.cloud.netflix.ribbon.SpringClientFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.client.RestTemplate;

import com.alibaba.fastjson.JSON;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.Server;
import com.netflix.loadbalancer.ZoneAwareLoadBalancer;
import com.roy.eureka.api.dto.User;
import com.roy.ribbon.MyRule;

@Controller
@RequestMapping(value = "ribbon")
public class RibbonController {
	/**
	 * 使用ribbon时注意ribbon实例的配置格式为 <instanceId>.ribbon.<key>=value
	 */
	private Logger logger = LoggerFactory.getLogger(RibbonController.class);
	
	private String instanceId = "EurekaDemo";//服务端的应用名
	/**
	 * 1、通过instance，ribbon会利用负载均衡策略选出一个服务地址进行调用。
	 */
	@Resource
	private LoadBalancerClient loadBalancerClient;

	@RequestMapping(value="/logInstance",method = RequestMethod.GET)
	@ResponseBody
	public Object logInstance() {
		ServiceInstance serviceInstance = loadBalancerClient.choose(instanceId);
		logger.info("serviceId: " + serviceInstance.getServiceId() + "; service host:" + serviceInstance.getHost()
				+ ";service port : " + serviceInstance.getPort());
		return serviceInstance;
	}
	/**
	 * 2、启动项上要添加注释@EnableEurekaClient
	 */
	@Resource
	private DiscoveryClient discoveryClient;
	@ResponseBody
	@GetMapping(value="/getServerList")
	public Object getServerList() {
		List<ServiceInstance> instances = discoveryClient.getInstances(instanceId);
		for(ServiceInstance instance:instances) {
			logger.info(JSON.toJSONString(instance));
		}
		return instances;
	}
	/**
	 * 3、restTemplate做负载均衡核心就是会在RestTemplate中添加个interceptor，从而将instanceId的访问地址转换成负载均衡选出的服务器地址
	 */
	@Bean
	@LoadBalanced
	public RestTemplate restTemplate() {
		return new RestTemplate();
	}
	
	@Resource
	private RestTemplate restTemplate;

	@RequestMapping(value = "/getSomeUsers", method = RequestMethod.GET)
	@ResponseBody
	public Object getSomeUsers(@RequestParam int countNum) {
		logger.info("Ribbon controller test i = " + 1);
		List<User> users = new ArrayList<User>();
		for (int i = 0; i < countNum; i++) {
			User user = new User();
			user.setUserId("" + i);
			users.add(user);
		}
		String url = "http://"+instanceId+"/user/getSomeUsers";
		List<?> userRes = restTemplate.postForObject(url, users, ArrayList.class);
		return userRes;
	}
	
	@RequestMapping(value="/getOneUsers/{id}",method=RequestMethod.GET)
	@ResponseBody
	public Object getOneUsers(@PathParam("id")String userId) {
		logger.info("Ribbon controller getOneUsers id = " + userId);
		User user = new User();
		user.setUserId(userId);
		String url = "http://"+instanceId+"/testServe/getOneUsers";
		User userInfo = restTemplate.postForObject(url, user, User.class);
		return userInfo;
	}
	/**
	 * 4、使用SpringClientFactory构建负载均衡器。
	 */
	@Autowired
	private SpringClientFactory factory;
	@Bean 
	//注入一个自定义rule
	public IRule getRule() {
		return new MyRule();
	}
	@RequestMapping(value = "/fa", method = RequestMethod.GET)
	public String factory() {
		ZoneAwareLoadBalancer lb = (ZoneAwareLoadBalancer)factory.getLoadBalancer("default");
		//加载的是IOC容器里的RULE
		String rn1 = lb.getRule().getClass().getName();
		logger.info("rn1 : "+rn1);
		Server ser1 = lb.chooseServer();
		logger.info("ser1 : "+ser1);
		
		ZoneAwareLoadBalancer lb2 = (ZoneAwareLoadBalancer)factory.getLoadBalancer(instanceId);
		//加载的是IOC容器里的RULE
		String rn2 = lb2.getRule().getClass().getName();
		logger.info("rn2 : "+rn2);
		Server ser2 = lb2.chooseServer();
		logger.info("ser2 : "+ser2);
		return "please see the console log";
	}
}
